<template>
	<view class="e-radio" @tap.stop="wrapperClickHandler" :style="[radioStyle]"
		:class="[ns.bm('label',radioGroupContext.props.iconPlacement), radioGroupContext.props.borderBottom && radioGroupContext.props.placement === 'column' && 'e-border-bottom']">
		<view class="e-radio__icon" @tap.stop="iconClickHandler">
			<slot name="icon" :isActive="isActive">
				<view class="e-radio__icon-wrap"  :class="iconClasses" :style="[iconWrapStyle]">
					<e-icon class="e-radio__icon-wrap__icon" name="checkbox-mark" :size="elIconSize" :color="elIconColor" />
				</view>
			</slot>
		</view>
		
		<text class="e-radio__text" @tap.stop="labelClickHandler" :style="{
				color: elDisabled ? elInactiveColor : elLabelColor,
				fontSize: elLabelSize,
				lineHeight: elLabelSize
			}">
			{{ props.label }}
		</text>
	</view>
</template>

<script lang="ts">
	import {defineComponent} from 'vue'
	import mpMixin from '../../libs/mixin/mpMixin'
	/**
	 * radio 单选框
	 * @description 单选框用于有一个选择，用户只能选择其中一个的场景。搭配e-radio-group使用
	 * @tutorial https://www.uviewui.com/components/radio.html
	 * @property {String | Number}	name			radio的名称
	 * @property {String}			shape			形状，square为方形，circle为圆型
	 * @property {Boolean}			disabled		是否禁用
	 * @property {String | Boolean}	labelDisabled	是否禁止点击提示语选中单选框
	 * @property {String}			activeColor		选中时的颜色，如设置parent的active-color将失效
	 * @property {String}			inactiveColor	未选中的颜色
	 * @property {String | Number}	iconSize		图标大小，单位px
	 * @property {String | Number}	labelSize		label字体大小，单位px
	 * @property {String | Number}	label			label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
	 * @property {String | Number}	size			整体的大小
	 * @property {String}			iconColor		图标颜色
	 * @property {String}			labelColor		label的颜色
	 * @property {Object}			customStyle		组件的样式，对象形式
	 * 
	 * @event {Function} change 某个radio状态发生变化时触发(选中状态)
	 * @example <e-radio :labelDisabled="false">门掩黄昏，无计留春住</e-radio>
	 */
	export default defineComponent({
		name: 'e-radio',
		mixins: [mpMixin]
	})
</script>

<script lang="ts" setup>
	import {
		ref,
		reactive,
		computed,
		nextTick,
		toRefs,
		provide,
		inject,
		onMounted,
		onBeforeUnmount
	} from 'vue'
	import {
		radioProps,
		radioEmits
	} from './props';
	import {
		radioGroupContextKey,
		radioContextKey,
		type RadioContext
	} from '../../libs/tokens'
	import {
		useNamespace,
		useFormItem,
		useDisabled,
		useDefaultProps
	} from '../../libs/hooks'
	import {
		deepMerge,
		empty
	} from '../../libs/utils'
	import {
		throwError,
		addUnit,
		addStyle,
		type propagationEvent
	} from '../../libs/utils/_utils'
	import type {
		StyleProperties
	} from '../../libs/tokens'
	import componentsProps from "../../libs/config/componentsProps";
	import type {
		 RadioProps
	} from "../../libs/config/propsType";
	
	const { radio: radioDefaultProps } = toRefs(componentsProps);

	const _props = defineProps(radioProps)
	const props = useDefaultProps < RadioProps> (_props, radioDefaultProps);
	const emit = defineEmits(radioEmits)

	const ns = useNamespace('radio')
	const {
		form,
		formItem
	} = useFormItem()

	const radioGroupContext = inject(radioGroupContextKey)
	if (!radioGroupContext) throwError('ERadio', 'e-radio需要结合e-radio-group组件使用')

	const isChecked = ref(false)
	// 是否禁用，如果父组件禁用的话，将会忽略子组件的配置
	const radioGroupContextDisabled = computed(() => radioGroupContext.props?.disabled)
	const elDisabled = useDisabled(radioGroupContextDisabled)
	// 是否禁用label点击
	const elLabelDisabled = computed(() => {
		return empty(props.value.labelDisabled) ? empty(radioGroupContext.props.labelDisabled) ? false : radioGroupContext
			.props.labelDisabled :
			props.value.labelDisabled;
	})


	// 组件尺寸，对应size的值，默认值为21px
	const elSize = computed(() => {
		return props.value.size ? props.value.size : (radioGroupContext.props.size ? radioGroupContext.props.size : 21);
	})
	// 组件的勾选图标的尺寸，默认12px
	const elIconSize = computed(() => {
		return props.value.iconSize ? props.value.iconSize : (radioGroupContext.props.iconSize ? radioGroupContext.props.iconSize : 12);
	})

	// 组件选中激活时的颜色
	const elActiveColor = computed(() => {
		return props.value.activeColor ? props.value.activeColor : (radioGroupContext.props.activeColor ? radioGroupContext
			.props.activeColor : '#2979ff');
	})
	// 组件选未中激活时的颜色
	const elInactiveColor = computed(() => {
		return props.value.inactiveColor ? props.value.inactiveColor : (radioGroupContext.props.inactiveColor ? radioGroupContext
			.props.inactiveColor :
			'#c8c9cc')
	})

	// label的颜色
	const elLabelColor = computed(() => {
		return props.value.labelColor ? props.value.labelColor : (radioGroupContext.props.labelColor ? radioGroupContext.props.labelColor :
			'#606266')
	})
	// 组件的形状
	const elShape = computed(() => {
		return props.value.shape ? props.value.shape : (radioGroupContext.props.shape ? radioGroupContext.props.shape : 'circle');
	})

	// label大小
	const elLabelSize = computed(() => {
		return addUnit(props.value.labelSize ? props.value.labelSize : (radioGroupContext.props.labelSize ? radioGroupContext
			.props.labelSize :
			'15'))
	})
	const elIconColor = computed(() => {
		const iconColor = props.value.iconColor ? props.value.iconColor : (radioGroupContext.props.iconColor ? radioGroupContext
			.props.iconColor :
			'#ffffff');
		// 图标的颜色
		if (elDisabled.value) {
			// disabled状态下，已勾选的checkbox图标改为elInactiveColor
			return isChecked.value ? elInactiveColor.value : 'transparent'
		} else {
			return isChecked.value ? iconColor : 'transparent'
		}
	})

	const iconClasses = computed(() => {
		let classes: string | string[] = []
		// 组件的形状
		classes.push('e-radio__icon-wrap--' + elShape.value)
		if (elDisabled.value) {
			classes.push('e-radio__icon-wrap--disabled')
		}
		if (isChecked.value && elDisabled.value) {
			classes.push('e-radio__icon-wrap--disabled--checked')
		}
		// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
		// #ifdef MP-ALIPAY || MP-TOUTIAO
		classes = classes.join(' ')
		// #endif
		return classes
	})
	
	const isActive = computed(() => isChecked.value && !elDisabled.value)

	const iconWrapStyle = computed(() => {
		// checkbox的整体样式
		const style: StyleProperties = {}
		style.backgroundColor = isActive.value ? elActiveColor.value : '#ffffff'
		style.borderColor = isActive.value ? elActiveColor.value : elInactiveColor.value
		style.width = addUnit(elSize.value)
		style.height = addUnit(elSize.value)
		// 如果是图标在右边的话，移除它的右边距
		if (radioGroupContext.props.iconPlacement === 'right') {
			style.marginRight = 0
		}
		return style
	})
	const radioStyle = computed(() => {
		const style: StyleProperties = {}
		if (radioGroupContext.props.borderBottom && radioGroupContext.props.placement === 'row') {
			throwError('ERadio', '检测到您将borderBottom设置为true，需要同时将e-radio-group的placement设置为column才有效')
		}
		// 当父组件设置了显示下边框并且排列形式为纵向时，给内容和边框之间加上一定间隔
		if (radioGroupContext.props.borderBottom && radioGroupContext.props.placement === 'column') {
			style.paddingBottom = '8px'
		}
		return deepMerge(style, addStyle(_props.customStyle as Record<string,any>) as Record<string,any>)
	})

	const init = () => {
		// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
		// 设置初始化时，是否默认选中的状态
		isChecked.value = radioGroupContext.props.modelValue === props.value.name
	}

	// 横向两端排列时，点击组件即可触发选中事件
	const wrapperClickHandler = (e: propagationEvent) => {
		radioGroupContext.props.iconPlacement === 'right' && iconClickHandler(e)
	}

	// 点击图标
	const iconClickHandler = (e: propagationEvent) => {
		// 如果整体被禁用，不允许被点击
		if (!elDisabled.value) {
			setRadioCheckedStatus()
		}
	}
	// 点击label
	const labelClickHandler = (e:propagationEvent) => {
		// 如果按钮整体被禁用或者label被禁用，则不允许点击文字修改状态
		if (!elLabelDisabled.value && !elDisabled.value) {
			setRadioCheckedStatus()
		}
	}

	const context: RadioContext = reactive({
		props,
		isChecked,
		init,
	})

	// 改变组件选中状态
	// 这里的改变的依据是，更改本组件的checked值为true，同时通过父组件遍历所有e-radio实例
	// 将本组件外的其他e-radio的checked都设置为false(都被取消选中状态)，因而只剩下一个为选中状态
	const setRadioCheckedStatus = () => {
		// 将本组件标记为与原来相反的状态
		isChecked.value = true
		emitEvent()
		typeof radioGroupContext.unCheckedOther === 'function' && radioGroupContext.unCheckedOther(context)
	}

	const emitEvent = () => {
		if (!isChecked.value) {
			emit('change', isChecked.value)
			// 尝试调用e-form的验证方法，进行一定延迟，否则微信小程序更新可能会不及时
			nextTick(() => {
				if (formItem && form) {
					form.validateField([formItem.props.prop], () => {}, 'change')
				}
			})
		}


	}

	onMounted(() => {
		init()
		if (radioGroupContext) {
			radioGroupContext.addField(context)
		}
	})

	onBeforeUnmount(() => {
		if (radioGroupContext) {
			radioGroupContext.removeField(context)
		}
		
	})

	provide(radioContextKey, context)
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/radio.scss";
</style>
